[WWDC18] NSSecureCodingで信頼性の高いデータのやり取りを #WWDC18
本記事は Apple からベータ版として公開されているドキュメントを情報源としています。 そのため、正式版と異なる情報になる可能性があります。ご留意の上、お読みください。
Data You Can Trust
A lot can go wrong when loading data into your app. Whether you work directly with JSON and property lists, or with higher-level APIs such as NSCoding and Codable, learn how to defend your customers and secure your code against invalid or malicious data. Avoid fatal assumptions by validating payload structure, type information and domain correctness, to turn the data you work with into data you can trust.
Validate First, Execute Later
WebAPIのレスポンスを受け取る際、第三者によってデータが改竄されるリスクもあります。 改竄されたデータを実行した際、アプリがクラッシュするなどの影響もあります。 それを防ぐために、バリデーションを最初に行い、その後コードの実行をすべきだと提言されました。 そのアプローチへの解の一つがセッションで紹介されました。
<br />func validate(_ listing: [String : Any]) throws { guard let id = listing["id"] as? Int, id > 0, id <= Int32.max else { throw ... } guard let urlString = listing["url"] as? String, urlString.count <= 50, let url URL(string: urlString) else { throw ... } guard url.host == "example.com" else { throw ... } } try listings.forEach(validate)
NSSecureCoding
- NSCodingでアーカイブして、データのやり取りを行う方法もあります
<br />class Purchase : NSCoding { required init?(coder: NSCoder) { guard let listing = coder.decodeObject(forKey: "listing") as? Listing else { return nil } self.listing = listing guard let data = coder.decodeObject(forKey: "purchaseDate") as? Date else { return nil } self.purchaseDate = date } } func savePurchase(_ purchase: Purchase) throws { let archive = NSKeyedArchiver.archivedData(withRootObject: purchase) try archive.write(to: /* storage location */) } func sloadPurchase() throws -> [Purchase] { let storage: [Data] = ... /* load from storage location */) return try storage.map { data in guard let object = try NSKeyedUnarchiver.unarchiveTopLevelObject(with: data), let purchase = object as? Purchase else { throw ... } return purchase } }
- その場合は
NSSecureCoding
を使うとより信頼性の高いデータのやり取りが行えますNSSecureCoding
はオブジェクト置換攻撃に対して堅牢な方法でエンコードとデコードを可能にするプロトコルです- NSSecureCoding
<br />class Purchase : NSSecureCoding { func encode(with coder: NSCoder) { ... } requierd init?(coder: NSCoder) { ... } class var supportSecureCoding: Bool { return true } }
- デコード方法
let data = NSKeyedArchiver.archivedData(withRootObject: myObject, requiringSecureCoding: true) let decode = NSKeyedUnarchiver.unarchivedObject(of: MyClass.self, from: data)
まとめ
NSSecureCoding
自体は新しく出た機能ではありませんが、アプリ側のセキュリティ要件を改めて満たすためには知っておいて損はない情報だと思いました。